package some

import (
	"fmt"
	"sort"

	"gitee.com/thubcc/p2pgit/classedpack"
	"gitee.com/thubcc/p2pgit/classify"
	"gitee.com/thubcc/p2pgit/types"
)

type prefixes []uint64

func (p prefixes) Len() int {
	return len(p)
}
func (p prefixes) Swap(i, j int) {
	p[i], p[j] = p[j], p[i]
}
func (p prefixes) Less(i, j int) bool {
	return p[i] < p[j]
}

// Gs2Prefix find prefix
func Gs2Prefix(gs types.SomeGeter) (p []prefixes, dir string, err error) {
	for i := 0; i < 65; i++ {
		p = append(p, prefixes{})
	}
	for _, v := range gs {
		if cpf, ok := v.(*classedpack.File); ok {
			dir = cpf.Dir
			if b, bok := cpf.C.(*classify.BasicClassify); bok {
				if b.BitLen > 64 || b.BitLen < 0 {
					err = fmt.Errorf("Bad geter: %s", b.String())
					return
				}
				p[b.BitLen] = append(p[b.BitLen], b.Prefix)
			}
		}
	}
	return
}

func dumpPrefix(p []prefixes) {
	for k, v := range p {
		if len(v) == 0 {
			continue
		}
		fmt.Printf("%4d: ", k)
		for _, i := range v {
			fmt.Printf("%x ", i)
		}
		fmt.Printf("\n")
	}
}

func up(p []prefixes, s int) []prefixes {
	if s == 0 {
		return p
	}
	if s > 64 {
		return p
	}
	m := p[s]
	sort.Sort(m)
	var np = prefixes{}
	var skip = false
	for k, v := range m {
		if skip {
			skip = false
			continue
		}
		if v%2 == 0 && k+1 < len(m) {
			if v+1 == m[k+1] {
				p[s-1] = append(p[s-1], v/2)
				skip = true
			}
		} else {
			np = append(np, v)
		}
	}
	p[s] = np
	return p
}

//MergeGeters Merge geter
func MergeGeters(igs types.SomeGeter) (ogs types.SomeGeter, err error) {
	var p []prefixes
	var dir string
	p, dir, err = Gs2Prefix(igs)
	if err != nil {
		return
	}
	for i := 64; i > 0; i-- {
		p = up(p, i)
	}
	for k, v := range p {
		if len(v) > 0 {
			for _, i := range v {
				g := &classedpack.File{
					C: &classify.BasicClassify{
						Prefix: i,
						BitLen: k,
					},
					Dir: dir,
				}
				ogs = append(ogs, g)
			}
		}
	}
	return
}

// Hiters2Prefix find prefix
func Hiters2Prefix(gs types.SomeHiter) (p []prefixes, err error) {
	for i := 0; i < 65; i++ {
		p = append(p, prefixes{})
	}
	for _, v := range gs {
		if c, ok := v.(*classedpack.Client); ok {
			if b, bok := c.C.(*classify.BasicClassify); bok {
				if b.BitLen > 64 || b.BitLen < 0 {
					err = fmt.Errorf("Bad hit: %s", b.String())
					return
				}
				p[b.BitLen] = append(p[b.BitLen], b.Prefix)
			} else {
				fmt.Println("Error", v)
			}
		}
	}
	return
}

//MergeHiters Merge geter
func MergeHiters(igs types.SomeHiter) (ogs types.SomeHiter, err error) {
	var p []prefixes
	p, err = Hiters2Prefix(igs)
	if err != nil {
		return
	}

	for i := 64; i > 0; i-- {
		p = up(p, i)
	}
	for k, v := range p {
		if len(v) > 0 {
			for _, i := range v {
				g := &classify.BasicClassify{
					Prefix: i,
					BitLen: k,
				}
				ogs = append(ogs, g)
				fmt.Println("install", g.String())
			}
		}
	}
	return
}
